package com.ftg.rbac.util;

import com.mysql.cj.jdbc.MysqlDataSource;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;


/**
 * 通用处理类
 *
 * @author kangjx
 * @version 1.0
 * @date 2023/3/16 上午9:13
 */
@SuppressWarnings("unused")
public class MybatisUtil {

    /* *******************实例化处理***************** */

    private SqlSession sessionInstance;
    private final SqlSessionFactory sqlSessionFactoryInstance;

    /**
     * mybatis实例方案的配置总类
     */
    private final Configuration config = new Configuration();

    /**
     * 当前系统默认处理方案
     *   默认只支持注解方案要想同上使用 xml 请使用  appendXml 方法向config添加配置文件
     */
    public MybatisUtil(){
        this("com.ftg.rbac.mapper","com.ftg.rbac.entity");
    }

    /**
     * 向config添加sql xml映射文件 ，并重新生成sessionInstance
     * @param xmlpath  新的xml文件地址
     */
    public void appendXml(String xmlpath){
        String otherName = xmlpath.substring(xmlpath.lastIndexOf("/") + 1);
        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(MybatisUtil.class.getResourceAsStream(xmlpath),config,otherName,config.getSqlFragments());
        xmlMapperBuilder.parse();
        //没有确认xml加载顺序，暂时每一次添加完成以后重新获得一个session以保证数据一致性问题
        this.sessionInstance = this.sqlSessionFactoryInstance.openSession();
    }

    /**
     * 通用处理部分
     * @param mapperPath  sql映射器地址
     * @param aliaPath    实体类存储地址
     */
    public MybatisUtil(String mapperPath,String aliaPath){

        // 配置
        config.setLogImpl(StdOutImpl.class);
        config.setCacheEnabled(true);

        // mapper接口
        config.addMappers(mapperPath);

        // 类别名  当这个包里面的所有类 名称首字母小写
        config.getTypeAliasRegistry().registerAliases(aliaPath);

        //事务
        TransactionFactory transactionFactory = new JdbcTransactionFactory();

        // 数据源
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setURL("jdbc:mysql://localhost:10086/rbac");
        dataSource.setUser("root");
        dataSource.setPassword("123456");

        //环境
        Environment e = new Environment("localmysql",transactionFactory,dataSource);
        config.setEnvironment(e);

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sqlSessionFactoryInstance = sqlSessionFactoryBuilder.build(config);
        sessionInstance = sqlSessionFactoryInstance.openSession();
    }


    public void retrySessionInstance(){
        sessionInstance = sqlSessionFactoryInstance.openSession();
    }

    /**
     * 获取当前对象
     * @param obj  对象反射
     * @return <T>
     * @param <T> 参数化泛型
     */
    public <T> T getNonStaticInstance(Class<T> obj){
        try{
            return sessionInstance.getMapper(obj);
        }catch (NullPointerException e){
            if(sessionInstance == null){
                retrySessionInstance();
                return sessionInstance.getMapper(obj);
            }
        }
        return null;
    }

    /**
     * 关闭session方法
     */
    public void closeNonStaticSession(){
        if(sessionInstance != null){
            sessionInstance.close();
        }
    }

    /**
     * 提交
     */
    public void  commitNonStaticSession(){
        if(sessionInstance != null){
            sessionInstance.commit();
        }
    }

    /**
     * 回滚
     */
    public void  commitNonStaticRollback(){
        if(sessionInstance != null){
            sessionInstance.rollback();
        }
    }

    /* ***************静态化处理******************* */

    /**
     * 缓存
     */
    private static SqlSession session;
    private static final SqlSessionFactory SQLSESSIONFACTORY;

    static {
        Configuration config = new Configuration();

        //  配置
        config.setLogImpl(StdOutImpl.class);
        config.setCacheEnabled(true);

        // 类别名  当这个包里面的所有类 名称首字母小写
        config.getTypeAliasRegistry().registerAliases("com.ftg.rbac.entity");
        config.getTypeAliasRegistry().registerAliases("com.ftg.rbac.vo");

        // mapper接口
        config.addMappers("com.ftg.rbac.mapper");

        //添加一个配置文件
        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(MybatisUtil.class.getResourceAsStream("../xml/User.xml"),config, "User.xml",config.getSqlFragments());
        xmlMapperBuilder.parse();

        // 事务
        TransactionFactory transactionFactory = new JdbcTransactionFactory();



        // 数据源
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setURL("jdbc:mysql://localhost:10086/rbac");
        dataSource.setUser("root");
        dataSource.setPassword("123456");

        //环境
        Environment e = new Environment("localmysql",transactionFactory,dataSource);
        config.setEnvironment(e);

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SQLSESSIONFACTORY = sqlSessionFactoryBuilder.build(config);
        session = SQLSESSIONFACTORY.openSession();
    }

    public static void  retrySession(){
        session = SQLSESSIONFACTORY.openSession();
    }

    /**
     * 获取当前对象
     * @param obj  对象反射
     * @return <T>
     * @param <T>  参数化泛型
     */
    public static <T> T getInstance(Class<T> obj){
        try{
            return session.getMapper(obj);
        }catch (NullPointerException e){
            if(session == null){
                retrySession();
                return session.getMapper(obj);
            }
        }
        return null;
    }

    /**
     * 关闭session方法
     */
    public static void  closeSession(){
        if(session != null){
            session.close();
        }
    }

    /**
     * 提交
     */
    public static void  commitSession(){
        if(session != null){
            session.commit();
        }
    }

    /**
     * 回滚
     */
    public static void  commitRollback(){
        if(session != null){
            session.rollback();
        }
    }

}
